package org.rainwalk.bill.util;

import cn.hutool.core.annotation.Alias;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.csv.CsvParser;
import cn.hutool.core.text.csv.CsvReadConfig;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvRowHandler;
import lombok.Data;
import org.rainwalk.bill.api.exception.BizException;
import org.rainwalk.bill.api.model.ResponseCode;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyCsvReader {

    public static void main(String[] args) {
        MyCsvReader reader = new MyCsvReader("----------", null);
        HashMap<String, Integer> headMap = new HashMap<>();
        headMap.put("交易时间", 0);
        headMap.put("交易类型", 1);
        headMap.put("交易对方", 2);
        headMap.put("商品", 3);
        headMap.put("收/支", 4);
        headMap.put("金额(元)", 5);
        headMap.put("支付方式", 6);
        headMap.put("当前状态", 7);
        headMap.put("交易单号", 8);
        headMap.put("商户单号", 9);
        headMap.put("备注", 10);
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader("F:\\Chrome下载\\微信支付账单(20210101-20210131)\\微信支付账单(20210101-20210131).csv"))) {
            List<WechatBill> read = reader.read(bufferedReader, WechatBill.class, headMap);
            System.out.println("");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Data
    class WechatBill {
        // 交易时间
        @Alias("交易时间")
        private String time;
        // 交易类型
        @Alias("交易类型")
        private String type;
        // 交易对方
        @Alias("交易对方")
        private String part;
        // 商品
        @Alias("商品")
        private String goodsName;
        // 收/支
        @Alias("收/支")
        private String fine;
        // 金额(元)
        @Alias("金额(元)")
        private String amount;
        // 支付方式
        @Alias("支付方式")
        private String payType;
        // 当前状态
        @Alias("当前状态")
        private String state;
        // 交易单号
        @Alias("交易单号")
        private String orderNo;
        // 商户单号
        @Alias("商户单号")
        private String merchantNo;
        // 备注
        @Alias("备注")
        private String remark;

    }

    /**
     * 数据开始，为null则从头开始读
     */
    private final String prefix;

    /**
     * 数据结束，为null则读取到最后
     */
    private final String suffix;

    public MyCsvReader(String prefix, String suffix) {
        this.prefix = prefix;
        this.suffix = suffix;
    }

    public <T> List<T> read(Reader reader, Class<T> clazz, Map<String, Integer> headMap) {
        final List<T> result = new ArrayList<>();
        read(reader, (row) -> {
            MyCsvRow myCsvRow = new MyCsvRow(row, headMap);
            result.add(myCsvRow.toBean(clazz));
        });
        return result;
    }

    private void read(Reader reader, CsvRowHandler rowHandler) {
        CsvReadConfig config = new CsvReadConfig();
        config.setContainsHeader(false);
        config.setSkipEmptyRows(true);
        config.setErrorOnDifferentFieldCount(false);
        read(new CsvParser(reader, config), rowHandler);
    }


    /**
     * 读取CSV数据，读取后关闭Parser
     *
     * @param csvParser  CSV解析器
     * @param rowHandler 行处理器，用于一行一行的处理数据
     * @throws IORuntimeException IO异常
     * @since 5.0.4
     */
    private void read(CsvParser csvParser, CsvRowHandler rowHandler) throws IORuntimeException {
        boolean isBegin = false;
        boolean skipTitle = false;
        boolean isEnd = false;
        try {
            CsvRow csvRow;
            while ((csvRow = csvParser.nextRow()) != null) {
                // 判断是否开始读取
                String firstField = csvRow.get(0);
                if (prefix == null) {
                    isBegin = true;
                } else if (! isBegin && firstField != null && firstField.contains(prefix)) {
                    isBegin = true;
                    continue;
                }

                if (! isBegin) {
                    continue;
                }

                if (! skipTitle) {
                    skipTitle = true;
                    continue;
                }

                // 判断是否已经读取完毕
                if (suffix != null && firstField.contains(suffix)) {
                    isEnd = true;
                }

                if (isEnd) {
                    break;
                }

                // 解析文件数据
                rowHandler.handle(csvRow);
            }
        } finally {
            IoUtil.close(csvParser);
        }
    }

    private class MyCsvRow {

        private CsvRow csvRow;

        public MyCsvRow(CsvRow csvRow, Map<String, Integer> headerMap) {
            if (csvRow.getFieldCount() > (headerMap.size() + 1)) {
                throw new BizException(ResponseCode.PARAMS_VERITY_FAIL, String.format("文件第%d行数据不正确", csvRow.getOriginalLineNumber()));
            }
            this.csvRow = new CsvRow(csvRow.getOriginalLineNumber(), headerMap, csvRow.getRawList());
        }

        public <T> T toBean(Class<T> clazz) {
            return csvRow.toBean(clazz);
        }
    }
}
